#define __DEC_ISR

#include <arch/idt.h>
#include <arch/vectors.h>
#include <arch/gdt.h>
#include <arch/interrupts.h>
#include <compiler.h>

#define IDT_ENTRY 255

u64 idt[IDT_ENTRY];
u16 idt_limit = sizeof(idt) - 1;

static inline void set_idt_entry(u32 vector, u16 seg_selector, void (*isr)(), u8 dpl, u8 type) {
    uptr offset = (uptr)isr;
    idt[vector] = (offset & 0xffff0000) | IDT_ATTR(dpl, type);
    idt[vector] <<= 32;
    idt[vector] |= (seg_selector << 16) | (offset & 0x0000ffff);
}

void set_idt_intr_entry(u32 vector, u16 seg_selector, void (*isr)(), u8 dpl) {
    set_idt_entry(vector, seg_selector, isr, dpl, IDT_INTERRUPT);
}

void set_idt_trap_entry(u32 vector, u16 seg_selector, void (*isr)(), u8 dpl) {
    set_idt_entry(vector, seg_selector, isr, dpl, IDT_TRAP);
}

int check_idt_exist(u32 vector) {
    return idt[vector] != 0;
}

void init_idt() {
    // CPU defined interrupts
    set_idt_intr_entry(FAULT_DIVISION_ERROR, SS_R0_CODE, __isr0, 0);
    set_idt_trap_entry(FAULT_TRAP_DEBUG_EXCEPTION, SS_R0_CODE, __isr1, 0);
    set_idt_intr_entry(FAULT_NON_MASKABLE, SS_R0_CODE, __isr2, 0);
    set_idt_intr_entry(FAULT_BRIDGE_CHECK, SS_R0_CODE, __isr3, 0);
    set_idt_intr_entry(TRAP_OVERFLOW, SS_R0_CODE, __isr4, 0);
    set_idt_intr_entry(FAULT_BOUND_EXCEED, SS_R0_CODE, __isr5, 0);
    set_idt_intr_entry(FAULT_INVALID_OPCODE, SS_R0_CODE, __isr6, 0);
    set_idt_intr_entry(FAULT_NO_MATH_PROCESSOR, SS_R0_CODE, __isr7, 0);
    set_idt_intr_entry(ABORT_DOUBLE_FAULT, SS_R0_CODE, __isr8, 0);
    set_idt_intr_entry(FAULT_RESERVED_0, SS_R0_CODE, __isr9, 0);
    set_idt_intr_entry(FAULT_INVALID_TSS, SS_R0_CODE, __isr10, 0);
    set_idt_intr_entry(FAULT_SEG_NOT_PRESENT, SS_R0_CODE, __isr11, 0);
    set_idt_intr_entry(FAULT_STACK_SEG_FAULT, SS_R0_CODE, __isr12, 0);
    set_idt_intr_entry(FAULT_GENERAL_PROTECTION, SS_R0_CODE, __isr13, 0);
    set_idt_trap_entry(FAULT_PAGE_FAULT, SS_R0_CODE, __isr14, 0);
    set_idt_intr_entry(FAULT_RESERVED_1, SS_R0_CODE, __isr15, 0);
    set_idt_trap_entry(FAULT_X87_FAULT, SS_R0_CODE, __isr16, 0);
    set_idt_intr_entry(FAULT_ALIGNMENT_CHECK, SS_R0_CODE, __isr17, 0);
    set_idt_intr_entry(FAULT_MACHINE_CHECK, SS_R0_CODE, __isr18, 0);
    set_idt_intr_entry(FAULT_SIMD_FLOATING_POINT, SS_R0_CODE, __isr19, 0);
    set_idt_intr_entry(FAULT_VIRTUALIZATION, SS_R0_CODE, __isr20, 0);
    set_idt_intr_entry(FAULT_CONTROL_PROTECTION, SS_R0_CODE, __isr21, 0);

    set_idt_intr_entry(KEYBOARD, SS_R0_CODE, __isr33, 0);
    set_idt_intr_entry(0x80, SS_R0_CODE, __isr128, 3); // system call
    set_idt_intr_entry(PIT_TIMER, SS_R0_CODE, __isr201, 0);
    set_idt_intr_entry(KEYBOARD, SS_R0_CODE, __isr202, 0);
    set_idt_intr_entry(AHCI_HBA_IV, SS_R0_CODE, __isr203, 0);
    set_idt_intr_entry(APIC_ERROR_IV, SS_R0_CODE, __isr250, 0);
    set_idt_intr_entry(APIC_LINT0_IV, SS_R0_CODE, __isr251, 0);
    set_idt_intr_entry(APIC_SPIV_IV, SS_R0_CODE, __isr252, 0);
    set_idt_intr_entry(APIC_TIMER_IV, SS_R0_CODE, __isr253, 0);
}